package com.example.service.impl;

import com.example.mapper.DeptLogMapper;
import com.example.mapper.DeptMapper;
import com.example.mapper.EmpMapper;
import com.example.pojo.Dept;
import com.example.pojo.DeptLog;
import com.example.service.DeptLogService;
import com.example.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private EmpMapper empMapper;

    @Autowired
    private DeptLogService deptLogService;

    @Override
    public List<Dept> list() {
        return deptMapper.list();
    }

    /**
     * - 在Spring的事务管理中，默认只有运行时异常 RuntimeException才会回滚。
     * - 如果还需要回滚指定类型的异常，可以通过rollbackFor属性来指定。
     * 所谓事务的传播行为，指的就是在A方法运行的时候，首先会开启一个事务，在A方法当中又调用了B方法， B方法自身也具有事务，那么B方法在运行的时候，到底是加入到A方法的事务当中来，还是B方法在运行的时候新建一个事务？这个就涉及到了事务的传播行为。
     * 在@Transactional注解的后面指定一个属性propagation，通过 propagation 属性来指定传播行为。
     * 对于这些事务传播行为，我们只需要关注以下两个就可以了：
     * 1. REQUIRED（默认值）：需要事务，有则加入，无则创建新事务
     * 2. REQUIRES_NEW：需要新事务，无论有无，总是创建新事务
     *
     * @param id
     * @throws Exception
     * @Transactional作用：就是在当前这个方法执行开始之前来开启事务，方法执行完毕之后提交事务。如果在这个方法执行的过程当中出现了异常，就会进行事务的回滚操作。
     * @Transactional注解：我们一般会在业务层当中来控制事务，因为在业务层当中，一个业务功能可能会包含多个数据访问的操作。在业务层来控制事务，我们就可以将多个数据访问操作控制在一个事务范围内。
     */
    @Transactional(rollbackFor = Exception.class) //spring事务管理
    @Override
    public void delete(Integer id) throws Exception {
        try {
            //根据ID删除部门数据
            deptMapper.deleteById(id);

            //模拟抛出异常：编译时异常
//            int i = 1 / 0;
//        if (true) {
//            throw new Exception("出错啦...");
//        }

            //根据部门ID删除该部门下的员工
            empMapper.deleteByDeptID(id);

        } finally {
            /**
             * DeptServiceImpl中的delete方法运行时，会开启一个事务。 当调用  deptLogService.insert(deptLog)  时，也会创建一个新的事务，那此时，当insert方法运行完毕之后，事务就已经提交了。
             * 即使外部的事务出现异常，内部已经提交的事务，也不会回滚了，因为是两个独立的事务。
             * - REQUIRED ：大部分情况下都是用该传播行为即可。
             * - REQUIRES_NEW ：当我们不希望事务之间相互影响时，可以使用该传播行为。比如：下订单前需要记录日志，不论订单保存成功与否，都需要保证日志记录能够记录成功。
             */
            DeptLog deptLog = new DeptLog();
            deptLog.setCreateTime(LocalDateTime.now());
            deptLog.setDescription("执行解散部门的操作, 此次解散的是" + id + "号部门");
            deptLogService.insert(deptLog); //记录操作日志
        }
    }

    @Override
    public void add(Dept dept) {
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.insert(dept);
    }

    @Override
    public Dept select(Integer id) {
        return deptMapper.selectById(id);
    }

    @Override
    public void update(Dept dept) {
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.update(dept);
    }
}
